/*  Copyright (c) 2003 PureSilk.Org  */
/* ====================================================================
 * 
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights 
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:  
 *       "This product includes software developed by the 
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written 
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */ 


/*
 * ActionServlet.java
 *
 * Created on April 17, 2003, 11:06 AM
 */

package org.puresilk.web;

import javax.servlet.*;
import javax.servlet.http.*;

import org.puresilk.web.actions.*;

/**
 * This class extends PSOServlet to enable an MVC Model 2 framework. All
 * Requests are searched for the 'action' parameter and this value is 
 * then passed to the ActionFactory to produce an WebAction that can
 * is loaded with a database connection and executed.  This results in
 * a jsp page specification for dispatching.
 *
 * @author  david
 * @version  .09
 */
public class ActionServlet extends PSOServlet {
    
    /** Serailizable id	 */
	private static final long serialVersionUID = -5118052048454594617L;
	/** action framework extension package */
    private String defActionPackage = null;
	private ActionFactory factory = null;
	private boolean enableSQL = false;
	private String defaultNoTargetPage = "/index.jsp";
	private String defaultErrorPage = "/error.jsp";
	
	
    /** 
     * Initializes the servlet for Action dispatch 
     * by queying the properties for action paths 
     * and packages.  
     */
    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        // get ready for action...
        String actionPath = getProperty("actionPath");
        
        if (actionPath == null) {
        	// create default factory
        	factory = new ActionFactory();
        }
        else {
        	// create custom class loader factory using path
        	String thePath = null;
        	
        	
        	if (actionPath.startsWith("/"))
				// if absolute path, use it as is
        		thePath = actionPath;
        	else 
        		// make path relative to application WEB-INF
				thePath = config.getServletContext().getRealPath("/WEB-INF") +
								"/" +
								actionPath;
											
			logDebugMsg("Action Path=" + thePath);
											
			// build factory with custom loader
			try {	
				factory = new ActionFactory("file://" + thePath);        		
			}
			catch (Exception ex) {
				log("Failed building ActionFactory", ex);
			}
						
        }
         
        // set up default action package name if we have it 
		defActionPackage = getProperty("actionPackage");
        if (null == defActionPackage)
            defActionPackage = "";
            
		logDebugMsg("Default Action Package=" + defActionPackage);            
    }
    
    /** Destroys the servlet.
     */
    public void destroy() {
        
    }
    
    //--------------------------------
    // Servlet operations
    //--------------------------------
    
    /** Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
    * @param request servlet request
    * @param response servlet response
    */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, java.io.IOException {
        // determine if this is an action based request
        String action = request.getParameter("action");
        String target = null;
        
        request.setAttribute("HTTPResponse", response);

        // execute the requested action on behalf of the client
        if ( action != null ) {
            logDebugMsg("Action = " + action);
            target = doAction(request);
        }
        
        
        // did we get a good returm?
        if ( target != null ) {
        	// should we dispatch to JSP?
        	if (target != Action.NO_JSP_DISPATCH) {
	            // yes,avoid jsp forward errors
	            if( target.charAt(0) != '/' ) {
	                logDebugMsg("Added '/' to " + target );
	                target = "/" + target;
	            }
	            
	            // fire up the specified JSP 
	            logDebugMsg("Action " + action + " forwarded to " + target);
	            RequestDispatcher rd = getServletContext().getRequestDispatcher(target);
	            rd.forward(request, response);
        	}
        }
        else {
            // Houston, we have a problem!
            logErrorMsg("No target page identified, Action:" + action);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
        // done
    } 

    /**
     * Perform action requested
     *
     * @param req servlet request 
     * @return target jsp page name 
     */
    protected String doAction ( HttpServletRequest req ) {
        // default return value
        String target = "/error.jsp";
        
        // establish action package
		String actionPackage = (String)req.getAttribute("actionPackage");         
        if (actionPackage == null)
        	actionPackage = defActionPackage;
        	
        // create the requested action	
        WebAction act =  factory.createAction(req, actionPackage );
        
        // No action created
        if (act == null){
        	// log error message
            logErrorMsg("No Action created for " + req.getParameter("action") + 
                   " (package=" + actionPackage + ").");
                   
			// dump exceptions to log                   
            log("AF Failed:", (Throwable) req.getAttribute("AFException"));
            target = getDefaultNoTargetPage();
        }
        else {
				//----------------------------------------
				// prepare new Action for action
				//----------------------------------------
        
				  // enable logging etc
				  act.setContext(this);
                
				  // run the action
				  target = act.execute(req);
        
				  // error check
				  if (target == null) {
					  logErrorMsg("No Target indentified. Error: " + req.getAttribute("Error"));
					  target=getDefaultErrorPage();
				  }    
            }
            
        // return results
        return target;
    }
    
    /** Retrieve action package */
    public void setActionPackage(String pkgName) {
        defActionPackage = pkgName;
    }
    
    /** set the action package  */
    public String getActionPackage( ) {
        return defActionPackage;
    }
    
    /** Returns a short description of the servlet.
     */
    public String getServletInfo() {
        return "Short description";
    }
    
    /** set missing action target page */
    protected void setDefaultNoTargetPage(String str){
        defaultNoTargetPage = str;
    }
    
    /** retrieve the missing action target page */
    protected String getDefaultNoTargetPage(){
        return defaultNoTargetPage;
    }
    
    /** set standard error page target */
    protected void setDefaultErrorPage(String str){
        defaultErrorPage = str;
    }
    
    /** retrieve the standard error page */
    protected String getDefaultErrorPage(){
        return defaultErrorPage;
    }

	public boolean isEnableSQL() {
		return enableSQL;
	}

	public void setEnableSQL(boolean enableSQL) {
		this.enableSQL = enableSQL;
	}
	
	public ActionFactory getFactory(){
		return factory;
	}
}
